//===============================================================================================//
// Copyright (c) 2012, Stephen Fewer of Harmony Security (www.harmonysecurity.com)
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted 
// provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, this list of 
// conditions and the following disclaimer.
// 
//     * Redistributions in binary form must reproduce the above copyright notice, this list of 
// conditions and the following disclaimer in the documentation and/or other materials provided 
// with the distribution.
// 
//     * Neither the name of Harmony Security nor the names of its contributors may be used to
// endorse or promote products derived from this software without specific prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
// POSSIBILITY OF SUCH DAMAGE.
//===============================================================================================//
#include "GetProcAddressR.h"
//===============================================================================================//
// We implement a minimal GetProcAddress to avoid using the native kernel32!GetProcAddress which
// wont be able to resolve exported addresses in reflectivly loaded librarys.
FARPROC WINAPI GetProcAddressR( HANDLE hModule, LPCSTR lpProcName )
{
    UINT_PTR uiLibraryAddress = 0;
    FARPROC fpResult          = NULL;

    if( hModule == NULL )
        return NULL;

    // a module handle is really its base address
    uiLibraryAddress = (UINT_PTR)hModule;

    __try
    {
        UINT_PTR uiAddressArray = 0;
        UINT_PTR uiNameArray    = 0;
        UINT_PTR uiNameOrdinals = 0;
        PIMAGE_NT_HEADERS pNtHeaders             = NULL;
        PIMAGE_DATA_DIRECTORY pDataDirectory     = NULL;
        PIMAGE_EXPORT_DIRECTORY pExportDirectory = NULL;
            
        // get the VA of the modules NT Header
        pNtHeaders = (PIMAGE_NT_HEADERS)(uiLibraryAddress + ((PIMAGE_DOS_HEADER)uiLibraryAddress)->e_lfanew);

        pDataDirectory = (PIMAGE_DATA_DIRECTORY)&pNtHeaders->OptionalHeader.DataDirectory[ IMAGE_DIRECTORY_ENTRY_EXPORT ];

        // get the VA of the export directory
        pExportDirectory = (PIMAGE_EXPORT_DIRECTORY)( uiLibraryAddress + pDataDirectory->VirtualAddress );
            
        // get the VA for the array of addresses
        uiAddressArray = ( uiLibraryAddress + pExportDirectory->AddressOfFunctions );

        // get the VA for the array of name pointers
        uiNameArray = ( uiLibraryAddress + pExportDirectory->AddressOfNames );
                
        // get the VA for the array of name ordinals
        uiNameOrdinals = ( uiLibraryAddress + pExportDirectory->AddressOfNameOrdinals );

        // test if we are importing by name or by ordinal...
        if( ((DWORD)lpProcName & 0xFFFF0000 ) == 0x00000000 )
        {
            // import by ordinal...

            // use the import ordinal (- export ordinal base) as an index into the array of addresses
            uiAddressArray += ( ( IMAGE_ORDINAL( (DWORD)lpProcName ) - pExportDirectory->Base ) * sizeof(DWORD) );

            // resolve the address for this imported function
            fpResult = (FARPROC)( uiLibraryAddress + DEREF_32(uiAddressArray) );
        }
        else
        {
            // import by name...
            DWORD dwCounter = pExportDirectory->NumberOfNames;
            while( dwCounter-- )
            {
                char * cpExportedFunctionName = (char *)(uiLibraryAddress + DEREF_32( uiNameArray ));
                
                // test if we have a match...
                if( strcmp( cpExportedFunctionName, lpProcName ) == 0 )
                {
                    // use the functions name ordinal as an index into the array of name pointers
                    uiAddressArray += ( DEREF_16( uiNameOrdinals ) * sizeof(DWORD) );
                    
                    // calculate the virtual address for the function
                    fpResult = (FARPROC)(uiLibraryAddress + DEREF_32( uiAddressArray ));
                    
                    // finish...
                    break;
                }
                        
                // get the next exported function name
                uiNameArray += sizeof(DWORD);

                // get the next exported function name ordinal
                uiNameOrdinals += sizeof(WORD);
            }
        }
    }
    __except( EXCEPTION_EXECUTE_HANDLER )
    {
        fpResult = NULL;
    }

    return fpResult;
}
//===============================================================================================//